package demo.dubbo;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.alibaba.dubbo.container.Main;
import com.alibaba.dubbo.container.spring.SpringContainer;

import demo.dubbo.provider.ProviderDemo;

/**
 * Main. (API, Static, ThreadSafe)
 * 
 * @author hanjy
 */
public class DubboMain {

    private static Logger logger = LoggerFactory.getLogger(DubboMain.class);

    private static final ReentrantLock LOCK = new ReentrantLock();

    private static final Condition STOP = LOCK.newCondition();

    @Test
    public void dubboStart1() {
        String springConfigPath = ProviderDemo.SPRING_CONFIG;
        startup1(springConfigPath);
    }

    @Test
    public void dubboStart2() {
        String springConfigPath = ProviderDemo.SPRING_CONFIG;
        startup2(springConfigPath);
    }

    @Test
    public void dubboStart3() {
        String springConfigPath = ProviderDemo.SPRING_CONFIG;
        startup3(springConfigPath);
    }

    /**
     * 通过com.alibaba.dubbo.container.Main启动spring容器
     * 
     * @param springConfigPath
     *            spring配置文件
     */
    public static void startup1(String springConfigPath) {
        // 设置Spring配置文件路径
        System.setProperty(SpringContainer.SPRING_CONFIG, springConfigPath);
        // 开启优雅停机
        System.setProperty(Main.SHUTDOWN_HOOK_KEY, "true");

        System.setProperty("dubbo.service.shutdown.wait", "10000");
        String[] array = { "spring" };
        Main.main(array);
    }

    /**
     * 通过ClassPathXmlApplicationContext启动spring容器
     * 
     * @param springConfigPath
     *            spring配置文件
     */
    public static void startup2(String springConfigPath) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(springConfigPath);
        Runtime.getRuntime().addShutdownHook(new Thread("dubbo-container-shutdown-hook") {
            @Override
            public void run() {
                try {
                    if (context != null) {
                        context.stop();
                        context.close();
                    }
                    logger.info("Dubbo  stopped!");
                } catch (Throwable t) {
                    logger.error(t.getMessage(), t);
                }
                try {
                    LOCK.lock();
                    STOP.signal();
                } finally {
                    LOCK.unlock();
                }
            }
        });
        context.start();
        logger.info("=============================STARTED=============================");

        try {
            LOCK.lock();
            STOP.await();
        } catch (InterruptedException e) {
            logger.warn("Dubbo service server stopped, interrupted by other thread!", e);
        } finally {
            LOCK.unlock();
        }
    }

    /**
     * 通过SpringContainer启动spring容器。
     * 
     * 使用 SpringContainer时，Dubbo 的ShutdownHook线程会执行ApplicationContext的stop和close方法，保证 Bean的生命周期完整。
     * 
     * @param springConfigPath
     *            spring配置文件
     */
    public static void startup3(String springConfigPath) {
        System.setProperty(SpringContainer.SPRING_CONFIG, springConfigPath);

        SpringContainer springContainer = new SpringContainer();
        Runtime.getRuntime().addShutdownHook(new Thread("dubbo-container-shutdown-hook") {
            @Override
            public void run() {
                try {
                    springContainer.stop();
                    logger.info("Dubbo " + springContainer.getClass().getSimpleName() + " stopped!");
                } catch (Throwable t) {
                    logger.error(t.getMessage(), t);
                }
                try {
                    LOCK.lock();
                    STOP.signal();
                } finally {
                    LOCK.unlock();
                }
            }
        });
        springContainer.start();
        logger.info("=============================STARTED=============================");
        try {
            LOCK.lock();
            STOP.await();
        } catch (InterruptedException e) {
            logger.warn("Dubbo service server stopped, interrupted by other thread!", e);
        } finally {
            LOCK.unlock();
        }
    }

}
